<script setup lang="ts">
//官网地址 https://www.wangeditor.com/v5/for-frame.html#demo-1
import {
  onMounted,
  onBeforeUnmount,
  computed,
  type PropType,
  unref,
  nextTick,
  ref,
  watch,
  shallowRef
} from 'vue';
//@ts-ignore
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import {
  type IDomEditor,
  type IEditorConfig,
  i18nChangeLanguage,
  type IToolbarConfig
} from '@wangeditor/editor';
import { propTypes } from '@/utils/propTypes';
import { isNumber } from '@/utils/is';
import { validateFileType, validateFileSize } from '@/utils/file';
import { ElMessage } from 'element-plus';
import { useLocaleStore } from '@/stores/modules/locale';
import { uploadFileAsync, fileApi } from '@/utils/api/file/index';

// 语言切换处理
const localeStore = useLocaleStore();
const currentLocale = computed(() => localeStore.getCurrentLocale);
i18nChangeLanguage(unref(currentLocale).lang);

// 定义props
const props = defineProps({
  editorId: propTypes.string.def('wangeEditor-1'),
  height: propTypes.oneOfType([Number, String]).def('500px'),
  editorConfig: {
    type: Object as PropType<Partial<IEditorConfig>>,
    default: () => undefined
  },
  toolbarConfig: {
    type: Object as PropType<Partial<IToolbarConfig>>,
    default: () => ({})
  },
  modelValue: propTypes.string.def('')
});

// 定义emits
const emits = defineEmits<{
  (e: 'update:modelValue', val: string): void;
  (e: 'change', editor: IDomEditor): void;
}>();

// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef<IDomEditor>();

// 定义编辑器内容参数
const valueHtml = ref('');

// 监听传入默认内容
watch(
  () => props.modelValue,
  (val: string) => {
    if (val === unref(valueHtml)) {
      return;
    }
    valueHtml.value = val;
  },
  {
    immediate: true
  }
);

// 监听内容变化则触发emits
watch(
  () => valueHtml.value,
  (val: string) => {
    emits('update:modelValue', val);
  }
);

// 创建编辑器
const handleCreated = (editor: IDomEditor) => {
  editorRef.value = editor;
};

// 菜单配置
const toolbarConfig = computed((): Partial<IToolbarConfig> => {
  return Object.assign(
    {
      //toolbarKeys: ["bold", "underline", "italic", "through", "code", "sub", "sup", "clearStyle", "color", "bgColor", "fontSize", "fontFamily", "indent", "delIndent", "justifyLeft", "justifyRight", "justifyCenter", "justifyJustify", "lineHeight", "insertImage", "deleteImage", "editImage", "viewImageLink", "imageWidth30", "imageWidth50", "imageWidth100", "divider", "emotion", "insertLink", "editLink", "unLink", "viewLink", "codeBlock", "blockquote", "headerSelect", "header1", "header2", "header3", "header4", "header5", "todo", "redo", "undo", "fullScreen", "enter", "bulletedList", "numberedList", "insertTable", "deleteTable", "insertTableRow", "deleteTableRow", "insertTableCol", "deleteTableCol", "tableHeader", "tableFullWidth", "insertVideo", "uploadVideo", "editVideoSize", "uploadImage", "codeSelectLang"],
      //excludeKeys: ['uploadVideo', 'insertVideo', 'editVideoSize']
    },
    props.toolbarConfig || {}
  );
});

// 编辑器配置
const editorConfig = computed((): Partial<IEditorConfig> => {
  return Object.assign(
    {
      readOnly: false, // 是否只读
      placeholder: '请输入内容...', // 提示文字
      autoFocus: false,
      scroll: true, // 是否开启滚动
      uploadImgShowBase64: true, // 是否将图片转成Base64上传
      MENU_CONF: {
        // 定义图片上传
        uploadImage: {
          // 上传之前触发
          onBeforeUpload(file: File) {
            // TS 语法
            if (validateFileType(file) && validateFileSize(file)) {
              return file;
            }
            return false;

            // 返回 false 或者 Promise 则停止上传
            // return false
            // 可以 return
            // 1. return file 或者 new 一个 file ，接下来将上传
            // 2. return false ，不上传这个 file
          },
          customUpload: async (
            file: File,
            insertFn: (url: string, alt: string, href: string) => void
          ) => {
            // 这里可以自定义上传
            const formData = new FormData();
            formData.append('formFile', file); // 根据后端文档，我需要传递file 和 flag 两个参数
            formData.append('projectName', 'omg'); // 根据后端文档，我需要传递file 和 flag 两个参数
            const result = await uploadFileAsync(formData); // 调用接口，将我们准备好的参数传递过去
            try {
              const url = `${fileApi.pictureAddress}/${result.md5}`;
              insertFn(url, result.name, url);
              return true;
            } catch (e) {
              console.log(e);
              return false;
            }
          }
        }
      },
      customAlert: (s: string, t: string) => {
        switch (t) {
          case 'success':
            ElMessage.success(s);
            break;
          case 'info':
            ElMessage.info(s);
            break;
          case 'warning':
            ElMessage.warning(s);
            break;
          case 'error':
            ElMessage.error(s);
            break;
          default:
            ElMessage.info(s);
            break;
        }
      }
    },
    props.editorConfig || {}
  );
});

// 编辑器样式
const editorStyle = computed(() => {
  return {
    height: isNumber(props.height) ? `${props.height}px` : props.height
  };
});

// 回调函数
const handleChange = (editor: IDomEditor) => {
  emits('change', editor);
};

// 组件销毁时，及时销毁编辑器
onBeforeUnmount(() => {
  const editor = unref(editorRef.value);

  // 销毁，并移除 editor
  editor?.destroy();
});

// 获取编辑器实例
const getEditorRef = async (): Promise<IDomEditor> => {
  await nextTick();
  return unref(editorRef.value) as IDomEditor;
};

onMounted(async () => {
  // 打印组件有那些菜单
  // const editor = await getEditorRef()
  // console.log(editor.getAllMenuKeys());
});

// 导出编辑器实例
defineExpose({
  getEditorRef
});
</script>

<template>
  <div class="border-1 border-solid border-[var(--el-border-color)] z-10">
    <!--工具栏-->
    <Toolbar
      :editor="editorRef"
      :editorId="editorId"
      :defaultConfig="toolbarConfig"
      class="border-0 b-b-1 border-solid border-[var(--el-border-color)]"
    />
    <!-- 编辑器 -->
    <Editor
      v-model="valueHtml"
      :editorId="editorId"
      :defaultConfig="editorConfig"
      :style="editorStyle"
      @on-change="handleChange"
      @on-created="handleCreated"
    />
  </div>
</template>
<style scoped lang="scss">
.border-0 {
  border-width: 0;
}

.border-1 {
  border-width: 1px;
}

.b-b-1 {
  border-bottom-width: 1px;
}

.border-solid {
  border-style: solid;
}

.border-\[var\(--el-border-color\)\] {
  border-color: var(--el-border-color);
}

.z-10 {
  z-index: 10;
}
</style>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style>
/* 暗色主题 */
html.dark {
  --w-e-textarea-bg-color: #333;
  --w-e-textarea-color: #fff;
  /* ...其他... */
}
</style>
